package com.flyemu.share.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.StrUtil;
import com.blazebit.persistence.PagedList;
import com.flyemu.share.controller.Page;
import com.flyemu.share.controller.PageResults;
import com.flyemu.share.dto.AccountDto;
import com.flyemu.share.dto.OrganizationDto;
import com.flyemu.share.entity.*;
import com.flyemu.share.repository.*;
import com.querydsl.core.BooleanBuilder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
@Slf4j
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class OrganizationService extends AbsService {

    private static final QOrganization qOrganization = QOrganization.organization;

    private final OrganizationRepository organizationRepository;
    private final UnitsRepository unitsRepository;
    private final WarehousesRepository warehousesRepository;
    private final ArgsSettingRepository argsSettingRepository;
    private final RelationCwRepository relationCwRepository;
    private final CustomersCategoryRepository customersCategoryRepository;
    private final VendorsCategoryRepository vendorsCategoryRepository;
    private final CustomersLevelRepository customersLevelRepository;
    private final RelationAccountRepository relationAccountRepository;
    private final static QArgsSetting qArgsSetting = QArgsSetting.argsSetting;
    private final static QRelationCw qRelationCw = QRelationCw.relationCw;

    private final CodeSeedService codeSeedService;

    private final QMerchant qMerchant = QMerchant.merchant;

    public PageResults<OrganizationDto> query(Page page, Query query) {
        PagedList<Organization> fetchPage = bqf.selectFrom(qOrganization).where(query.builder).orderBy(qOrganization.id.desc()).fetchPage(page.getOffset(),page.getOffsetEnd());

        List<OrganizationDto> dtos = new ArrayList<>();
        fetchPage.forEach(tuple -> {
            Organization organization = tuple;
            OrganizationDto organizationDto = BeanUtil.toBean(organization, OrganizationDto.class);
            dtos.add(organizationDto);
        });

        return new PageResults<>(dtos, page, fetchPage.getTotalSize());
    }


    /**
     *  init 加载组织列表
     * @param merchantId
     * @return
     */
    public List<Dict> loadOrg(Long merchantId) {
        List<Dict> dictList = new ArrayList<>();
         bqf.selectFrom(qOrganization).select(qOrganization.id,qOrganization.name,qOrganization.current,qOrganization.startDate,qOrganization.checkoutDate).where(qOrganization.merchantId.eq(merchantId))
                .orderBy(qOrganization.id.desc()).fetch().forEach(tuple->{
                    Dict dict = new Dict().set("key",tuple.get(qOrganization.id))
                            .set("title",tuple.get(qOrganization.name))
                            .set("startDate",tuple.get(qOrganization.startDate))
                            .set("checkoutDate",tuple.get(qOrganization.checkoutDate))
                            .set("current",tuple.get(qOrganization.current));
                    dictList.add(dict);
                 });
        return dictList;
    }

    @Transactional
    public AccountDto changeOrgCurrent(Long merchantId, Long orgId, AccountDto accountDto) {
        jqf.update(qOrganization)
                .set(qOrganization.current,false)
                .where(qOrganization.merchantId.eq(merchantId)).execute();
        jqf.update(qOrganization)
                .set(qOrganization.current,true)
                .where(qOrganization.merchantId.eq(merchantId).and(qOrganization.id.eq(orgId))).execute();


        Organization organization = bqf.selectFrom(qOrganization).where(qOrganization.merchantId.eq(merchantId).and(qOrganization.id.eq(orgId))).fetchFirst();

        String costMethod = bqf.selectFrom(qArgsSetting).select(qArgsSetting.costMethod).where(qArgsSetting.merchantId.eq(merchantId).and(qArgsSetting.organizationId.eq(organization.getId()))).fetchFirst();
        Long accountSetsId = bqf.selectFrom(qRelationCw).select(qRelationCw.accountSetsId).where(qRelationCw.merchantId.eq(merchantId).and(qRelationCw.organizationId.eq(organization.getId()))).fetchFirst();

        accountDto.setOrganization(organization);
        accountDto.setCostMethod(costMethod);
        accountDto.setAccountSetsId(accountSetsId);
        accountDto.setCheckDate(organization.getCheckoutDate() != null ? organization.getCheckoutDate() : organization.getStartDate());
        return accountDto;
    }


    /**
     * 保存
     *
     * @param organizationForm
     * @return
     */
    @Transactional
    public Organization save(OrganizationDto organizationForm) {
       if(bqf.selectFrom(qOrganization)
               .where(qOrganization.merchantId.eq(organizationForm.getMerchantId())).fetchCount()<=0) {
           organizationForm.setCurrent(true);
       }
        if (organizationForm.getId() != null) {
            //更新
            Organization original = organizationRepository.getById(organizationForm.getId());
            BeanUtil.copyProperties(organizationForm, original, CopyOptions.create().ignoreNullValue());
            return organizationRepository.save(original);
        }

        Organization organization = BeanUtil.toBean(organizationForm, Organization.class);
        organization.setEnabled(true);
        organization.setCreateDate(LocalDateTime.now());
        if (StrUtil.isEmpty(organization.getCode())) {
            //如果没有设置，则使用系统生成
            String merchantCode = bqf.selectFrom(qMerchant)
                    .select(qMerchant.code)
                    .where(qMerchant.id.eq(organization.getMerchantId()))
                    .fetchOne();
            Integer nextSeed = codeSeedService.next(organization.getMerchantId(), merchantCode);
            organization.setCode("S" + merchantCode + nextSeed);
        } else {
            //手动设置了编码，需要检查重复
            long count = bqf.selectFrom(qOrganization)
                    .where(qOrganization.merchantId.eq(organization.getMerchantId()).and(qOrganization.code.eq(organization.getCode())))
                    .fetchCount();
            Assert.isTrue(count == 0, organization.getCode() + "编码已存在~");
        }
        Organization org = organizationRepository.save(organization);

        ArgsSetting argsSetting = new ArgsSetting();
        argsSetting.setMerchantId(organization.getMerchantId());
        argsSetting.setOrganizationId(organization.getId());
        argsSetting.setCostMethod("平");
        argsSettingRepository.save(argsSetting);

        RelationCw relationCw = new RelationCw();
        relationCw.setOrganizationId(organization.getId());
        relationCw.setMerchantId(organization.getMerchantId());
        relationCw.setIsRelation(false);
        relationCwRepository.save(relationCw);

        //初始化单位
        String[] units = {"斤", "公斤", "袋", "盒", "条", "克", "瓶", "包", "箱", "个", "只", "罐", "块", "毫升", "桶", "听", "件", "张", "套", "付", "台", "串", "根", "本", "把", "双", "副", "捆", "管", "元", "组", "米", "份", "盘", "支", "粒", "片"};
        for (String unit : units) {
            Units u = new Units();
            u.setMerchantId(org.getMerchantId());
            u.setOrganizationId(org.getId());
            u.setName(unit);
            unitsRepository.save(u);
        }

        //初始化仓库
        Warehouses warehouses = new Warehouses();
        warehouses.setName("默认仓库");
        warehouses.setEnabled(true);
        warehouses.setCode("000");
        warehouses.setCreateDate(new Date());
        warehouses.setIsDefault(true);
        warehouses.setOrganizationId(org.getId());
        warehouses.setMerchantId(org.getMerchantId());
        warehousesRepository.save(warehouses);

        //初始化客户分类
        CustomersCategory customersCategory = new CustomersCategory();
        customersCategory.setMerchantId(org.getMerchantId());
        customersCategory.setOrganizationId(org.getId());
        customersCategory.setCode("000");
        customersCategory.setName("默认分类");
        customersCategoryRepository.save(customersCategory);

        //初始化货商分类
        VendorsCategory vendorsCategory = new VendorsCategory();
        vendorsCategory.setMerchantId(org.getMerchantId());
        vendorsCategory.setOrganizationId(org.getId());
        vendorsCategory.setCode("000");
        vendorsCategory.setName("默认分类");
        vendorsCategoryRepository.save(vendorsCategory);

        //初始化客户级别
        CustomersLevel customersLevel = new CustomersLevel();
        customersLevel.setMerchantId(org.getMerchantId());
        customersLevel.setOrganizationId(org.getId());
        customersLevel.setName("零售客户");
        customersLevelRepository.save(customersLevel);
        return organization;
    }

    /**
     * 删除
     *
     * @param merchantId
     * @param organizationId
     */
    @Transactional
    public void delete(Long merchantId, Long organizationId) {
        QOrder qOrder = QOrder.order;
        long count = bqf.selectFrom(qOrder).where(qOrder.organizationId.eq(organizationId)).fetchCount();
        Assert.isTrue(count == 0, "已被使用不能删除~");
        jqf.delete(qOrganization)
                .where(qOrganization.merchantId.eq(merchantId).and(qOrganization.id.eq(organizationId)))
                .execute();
    }

    /**
     * 根据ID获取数据
     *
     * @param orgId
     * @return
     */
    public Organization loadById(Long merchantId, Long orgId) {
        return bqf.selectFrom(qOrganization)
                .where(qOrganization.merchantId.eq(merchantId).and(qOrganization.id.eq(orgId)))
                .fetchFirst();
    }

    public List<Organization> listAll(Long merchantId) {
        return bqf.selectFrom(qOrganization)
                .where(qOrganization.merchantId.eq(merchantId).and(qOrganization.enabled.isTrue()))
                .orderBy(qOrganization.code.asc())
                .fetch();
    }

    public List<Organization> select(Long merchantId) {
        return bqf.selectFrom(qOrganization).where(qOrganization.merchantId.eq(merchantId).and(qOrganization.enabled.isTrue())).fetch();
    }

    @Transactional
    public void update(Organization organization) {
        if (organization.getId() != null) {
            //更新
            Organization original = organizationRepository.getById(organization.getId());
            BeanUtil.copyProperties(organization, original, CopyOptions.create().ignoreNullValue());
            organizationRepository.save(original);
        }
    }

    /**
     * 查询条件
     */
    public static class Query {
        public final BooleanBuilder builder = new BooleanBuilder();

        public void setName(String name) {
            if (StrUtil.isNotEmpty(name)) {
                builder.and(qOrganization.name.contains(name));
            }
        }

        public void setMerchantId(Long merchantId) {
            if (merchantId != null) {
                builder.and(qOrganization.merchantId.eq(merchantId));
            }
        }
    }
}
